package Model.Draw.Entities;

import Model.Draw.Entities.Impl.StateJoint;
import Model.Draw.Entities.Impl.StateLine;
import Model.Draw.IStateDraw;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.font.FontRenderContext;
import java.awt.font.LineMetrics;
import java.awt.geom.RoundRectangle2D;

public class StateDraw implements IStateDraw {

    private StateLine left;
    private StateLine top;
    private StateLine right;
    private StateLine bottom;
    private String stateName;
    private RoundRectangle2D rectangle;
    private boolean selected;

    public StateDraw() {
        selected = false;
        stateName = "novo estado";
    }

    public Color getColor() {
        return selected ? Color.RED : Color.BLACK;
    }

    /**
     * @return the left
     */
    public StateLine getLeft() {
        return left;
    }

    /**
     * @param left the left to set
     */
    public void setLeft(StateLine left) {
        this.left = left;
    }

    /**
     * @return the top
     */
    public StateLine getTop() {
        return top;
    }

    /**
     * @param top the top to set
     */
    public void setTop(StateLine top) {
        this.top = top;
    }

    /**
     * @return the right
     */
    public StateLine getRight() {
        return right;
    }

    /**
     * @param right the right to set
     */
    public void setRight(StateLine right) {
        this.right = right;
    }

    /**
     * @return the bottom
     */
    public StateLine getBottom() {
        return bottom;
    }

    /**
     * @param bottom the bottom to set
     */
    public void setBottom(StateLine bottom) {
        this.bottom = bottom;
    }

    @Override
    public void draw(Graphics g) {
        Graphics2D g2 = (Graphics2D) g;
        g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                RenderingHints.VALUE_ANTIALIAS_ON);
        FontRenderContext frc = g2.getFontRenderContext();
        Font font = g2.getFont().deriveFont(16f);
        g2.setFont(font);
        g2.setColor(getColor());
        int width = (int) (getTop().getExtreamTargetPoint().getX().getCoordinate() - getTop().getExtreamSourcePoint().getX().getCoordinate());
        if (width < 0) {
            width = width * -1;
        }
        int height = (int) (getLeft().getExtreamTargetPoint().getY().getCoordinate() - getLeft().getExtreamSourcePoint().getY().getCoordinate());
        if (height < 0) {
            height = height * -1;
        }
        rectangle = new RoundRectangle2D.Double(getTop().getMoreLeftPoint().getX().getCoordinate(), getTop().getMoreLeftPoint().getY().getCoordinate(), width, height, 20, 20);
        g2.setPaint(Color.pink);
        g2.fill(rectangle);
        g2.setPaint(getColor());
        g2.draw(rectangle);
        float sw = (float) font.getStringBounds(stateName, frc).getWidth();
        LineMetrics lm = font.getLineMetrics(stateName, frc);
        float sh = lm.getAscent() + lm.getDescent();
        double sx = rectangle.getX() + (rectangle.getWidth() - sw) / 2;
        double sy = rectangle.getY() + (rectangle.getHeight() + sh) / 2 - lm.getDescent();
        g2.setPaint(Color.BLACK);
        g2.drawString(stateName, (float) sx, (float) sy);
        g2.setColor(getColor());
        g2.drawOval((int) left.getJoint().getX().getCoordinate() - 3, (int) left.getJoint().getY().getCoordinate() - 3, 6, 6);
        g2.fillOval((int) left.getJoint().getX().getCoordinate() - 3, (int) left.getJoint().getY().getCoordinate() - 3, 6, 6);
        g2.drawOval((int) right.getJoint().getX().getCoordinate() - 3, (int) right.getJoint().getY().getCoordinate() - 3, 6, 6);
        g2.fillOval((int) right.getJoint().getX().getCoordinate() - 3, (int) right.getJoint().getY().getCoordinate() - 3, 6, 6);
        g2.drawOval((int) top.getJoint().getX().getCoordinate() - 3, (int) top.getJoint().getY().getCoordinate() - 3, 6, 6);
        g2.fillOval((int) top.getJoint().getX().getCoordinate() - 3, (int) top.getJoint().getY().getCoordinate() - 3, 6, 6);
        g2.drawOval((int) bottom.getJoint().getX().getCoordinate() - 3, (int) bottom.getJoint().getY().getCoordinate() - 3, 6, 6);
        g2.fillOval((int) bottom.getJoint().getX().getCoordinate() - 3, (int) bottom.getJoint().getY().getCoordinate() - 3, 6, 6);
    }

    @Override
    public boolean contains(int x, int y) {
        if (rectangle != null) {
            return rectangle.contains(x, y);
        }
        return false;
    }

    @Override
    public void select() {
        selected = true;
    }

    @Override
    public void unselect() {
        selected = false;
    }

    @Override
    public void move(int newX, int newY) {
        int oldX = (int) getTop().getMoreLeftPoint().getX().getCoordinate() + (int) rectangle.getWidth() / 2;
        int oldY = (int) getTop().getMoreLeftPoint().getY().getCoordinate() + (int) rectangle.getHeight() / 2;
        int diffX = newX - oldX;
        int diffY = newY - oldY;

        left.move(diffX, diffY);
        right.move(diffX, diffY);
        top.move(diffX, diffY);
        bottom.move(diffX, diffY);
    }

    @Override
    public void rename(String newName) {
        stateName = newName;
    }

    @Override
    public StateJoint findNearstJointOf(IStateDraw otherDraw) {
        if (otherDraw instanceof StateDraw) {
            if (left.getJoint().getX().getCoordinate() < ((StateDraw) otherDraw).left.getJoint().getX().getCoordinate()) {
                if (right.getJoint().getX().getCoordinate() < ((StateDraw) otherDraw).left.getJoint().getX().getCoordinate()) {
                    return right.getJoint();
                } else {
                    if (top.getJoint().getY().getCoordinate() > ((StateDraw) otherDraw).top.getJoint().getY().getCoordinate()) {
                        return top.getJoint();
                    } else {
                        return bottom.getJoint();
                    }
                }
            } else {
                if (left.getJoint().getX().getCoordinate() < ((StateDraw) otherDraw).right.getJoint().getX().getCoordinate()) {
                    if (top.getJoint().getY().getCoordinate() < ((StateDraw) otherDraw).top.getJoint().getY().getCoordinate()) {
                        return bottom.getJoint();
                    } else {
                        return top.getJoint();
                    }
                } else {
                    return left.getJoint();
                }
            }
        }
        return null;
    }

    @Override
    public String getDescription() {
        return stateName;
    }
}
